package com.spsoft.vatoutinv.service.official.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.XML;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.DateUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.entity.*;
import com.spsoft.system.mapper.NvatOutInvoiceItemsMapper;
import com.spsoft.system.model.bo.official.BussinessBO;
import com.spsoft.system.model.vo.official.*;
import com.spsoft.system.service.*;
import com.spsoft.vatoutinv.config.InterfaceProperties;
import com.spsoft.vatoutinv.config.Sm4Properties;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsepsInformation.VmsEpsInformation;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceDetails;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceItems;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceItemsExp;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.LzfpbzEnum;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceInfoDto;
import com.spsoft.vatoutinv.service.issueinvoice.IssueInvoiceService;
import com.spsoft.vatoutinv.service.official.OfficialDealInvoiceService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsepsInformation.VmsEpsInformationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Component
public class OfficialDealInvoiceServiceImpl implements OfficialDealInvoiceService {
    /**
     * 交易数据信息表
     */
    private final NvatTrandtadvaltaxsepService nvatTrandtadvaltaxsepService;

    /**
     * 应用参数配置
     */
    private final BiDataConfigInfoService biDataConfigInfoService;

    /**
     * 负数流水管理
     */
    private final NvatNegativestreamService negativestreamService;

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;
    /**
     * 企业商品及服务
     */
    private final VmsEpsInformationService epsInformationService;

    /**
     * 开票接口
     */
    private final IssueInvoiceService issueInvoiceService;

    /**
     * 发票主表信息
     */
    private final NvatOutinvoicedetailsService nvatOutinvoicedetailsService;
    /**
     * 发票明细
     */
    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;
    private final SequenceService sequenceService;
    /**
     * 流水发票关联关系
     */
    private final NvatRevmapinvoitemsService nvatRevmapinvoitemsService;
    /**
     * 老系统的企业商品及服务信息
     */
    private final NvatSxcpbXinhuaService nvatSxcpbXinhuaService;
    private final InterfaceProperties interfacesProperties;

    private final Sm4Properties sm4Properties;
    /**
     * 数电票逻辑处理
     * @param transactionFlowMerge
     * @param wkpFlowList
     * @param bswj
     * @param dataSource
     * @param downloadVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result<InvoiceDownloadVO> dealSdpResult(TransactionFlowVO transactionFlowMerge,
                                                   List<TransactionFlowVO> wkpFlowList,
                                                   VmsFullBswjManager bswj, CommonEnum dataSource, InvoiceDownloadVO downloadVO) {
        List<VmsFullOutInvoiceInfoDto> vmsFullOutInvoiceInfoDtos = this.buildSdpParam(transactionFlowMerge, wkpFlowList, bswj, dataSource);
        TokenUser tokenUser = new TokenUser();
        tokenUser.setUserCode(dataSource.getValue());
        tokenUser.setUserName(dataSource.getValue());
        tokenUser.setDeptCode(transactionFlowMerge.getJYJG());
        // 更新流水表等数据库操作
        List<Long> wkpRdids = wkpFlowList.stream().map(TransactionFlowVO::getRDID).collect(Collectors.toList());
        List<Long> wkpNegRdids = wkpFlowList.stream()
                .filter(f -> f.getJYJE().compareTo(new BigDecimal("0")) < 0)
                .map(TransactionFlowVO::getRDID).collect(Collectors.toList());
        // 更新交易流水表
        boolean updateReulst = this.updateDatabase(wkpRdids, wkpNegRdids, dataSource.getValue());
        if (!updateReulst) {
            this.rollbackDatabase(wkpFlowList, wkpNegRdids, dataSource.getValue());
            return Result.ERROR(ResponseEnum.OFFICIAL_LSZT_ERROR);
        }

        // 调用数电票接口，开具发票，
        // 返回BusinessException，则需要向上返回，事务不会滚
        // 返回Exception异常，则是系统异常，需要事务回滚
        Result<Object> sdpFphm = null;
        try {
            sdpFphm = issueInvoiceService.issueInvoice(vmsFullOutInvoiceInfoDtos, tokenUser);
        } catch (Exception e) {
            // TODO 加预警，需要人工干预
            log.error("{}调用数电票接口，系统异常，业务编号：{}", dataSource.getValue(), transactionFlowMerge.getYWBH());
            throw e;
        }

        // 处理返回结果，异常不回滚事务
        try {
            if (sdpFphm!=null && !sdpFphm.getCode().equals(ResponseEnum.SUCCESS.getCode())) {
                StringBuilder msgSb = new StringBuilder(sdpFphm.getMessage());
                if (sdpFphm.getData() != null) {
                    msgSb.append("内容为：");
                    msgSb.append(JSONUtil.toJsonStr(sdpFphm.getData()));
                }
                // 回滚数据
                this.rollbackDatabase(wkpFlowList, wkpNegRdids, dataSource.getValue());
                return Result.ERRORT(sdpFphm.getCode(), msgSb.toString());
            }
            // 处理返回下载地址链接
            List<String> fphms = (List<String>) sdpFphm.getData();
            String fphm = fphms.get(0);

            SdpXzdzVO dz = OfficialServiceCommonMtd.getSdpXzdzVO(fphm, interfacesProperties.getSdpDownloadUrlPrefix(), sm4Properties.getKey().getBytes());
            if (downloadVO.getSdpXzdzList() == null) {
                List<SdpXzdzVO> sdpXzdzList = new ArrayList<>();
                sdpXzdzList.add(dz);
                downloadVO.setSdpXzdzList(sdpXzdzList);
            } else {
                downloadVO.getSdpXzdzList().add(dz);
            }

            // 返回下载链接去重后结果
            return OfficialServiceCommonMtd.uniqueSdpList(downloadVO);
        } catch (Exception e) {
            // TODO 加预警，人工干预
            log.error("{}处理数电票返回值异常，业务编号：{}", dataSource.getValue(), transactionFlowMerge.getYWBH());
            return Result.ERROR();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Result<InvoiceDownloadVO> dealDzfpResult(TransactionFlowVO transactionFlowMerge,
                                                    List<TransactionFlowVO> wkpFlowList,
                                                    CommonEnum datasource,
                                                    InvoiceDownloadVO downloadVO) {
        Map<BigDecimal, List<TransactionFlowVO>> collect = wkpFlowList.stream().collect(Collectors.groupingBy(TransactionFlowVO::getSYSL));
        Map<BigDecimal, NvatSxcpbXinhua> epsXinhuaMap = this.buildOldEpsMap(collect, datasource.getValue());

        Map<BigDecimal, TransactionFlowVO> fpmxMap = new HashMap<>();
        // 查询产品名称、交易流水根据税率进行合并
        collect.keySet().forEach(sl -> {
            List<TransactionFlowVO> slFlowList =  collect.get(sl);
            TransactionFlowVO fpmx = new TransactionFlowVO();
            BeanUtils.copyBeanProp(fpmx, collect.get(sl).get(0));
            fpmx.setJYRMBJE(slFlowList.stream().map(TransactionFlowVO::getJYRMBJE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setBHSJE(slFlowList.stream().map(TransactionFlowVO::getBHSJE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setXXSE(slFlowList.stream().map(TransactionFlowVO::getXXSE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setJYJE(slFlowList.stream().map(TransactionFlowVO::getJYJE).reduce(BigDecimal.ZERO, BigDecimal::add));

            NvatSxcpbXinhua eps = epsXinhuaMap.get(sl);
            fpmx.setCpmc("*"+eps.getSpjc()+"*保费");
            fpmx.setRdidsStr(slFlowList.stream().map(vo -> vo.getRDID().toString()).collect(Collectors.joining("、")));
            fpmxMap.put(sl, fpmx);
        });
        // 拼装调用税控平台参数
        List<Long> wkpRdids = wkpFlowList.stream().map(TransactionFlowVO::getRDID).collect(Collectors.toList());
        BussinessBO bussinessBO = this.buildBussinessBO(transactionFlowMerge, wkpRdids, fpmxMap, epsXinhuaMap);

        // 修改交易流水状态
        List<Long> wkpNegRdids = wkpFlowList.stream()
                .filter(f -> f.getJYJE().compareTo(new BigDecimal("0")) < 0)
                .map(TransactionFlowVO::getRDID).collect(Collectors.toList());
        // 更新交易流水表
        boolean updateReulst = this.updateDatabase(wkpRdids, wkpNegRdids, datasource.getValue());
        if (!updateReulst) {
            this.rollbackDatabase(wkpFlowList, wkpNegRdids, datasource.getValue());
            return Result.ERROR(ResponseEnum.OFFICIAL_LSZT_ERROR);
        }
        Rtnmsg rtnmsg = this.dzfpPostXml(bussinessBO);

        // 处理税控平台返回值, 事务不回滚
        try {
            if ("4000".equals(rtnmsg.getReturncode())) {
                String nssbh = nvatTrandtadvaltaxsepService.queryNssbhByJyjg(transactionFlowMerge.getJYJG());
                String dzfpUrlPrefix = biDataConfigInfoService.getEDonwloadUrlPrefix();
                String dzfpdz = OfficialServiceCommonMtd.getDzfpUrl(dzfpUrlPrefix, rtnmsg.getReturndata().getFpdm(), rtnmsg.getReturndata().getFphm(), nssbh);
                downloadVO.getDzfpXzdz().add(dzfpdz);
                // 保存发票信息、发票明细、发票流水关联表
                insertDatabase(bussinessBO, collect, transactionFlowMerge, rtnmsg, epsXinhuaMap, datasource);

                return OfficialServiceCommonMtd.uniqueSdpList(downloadVO);
            } else {
                // 回滚交易流水状态
                this.rollbackDatabase(wkpFlowList, wkpNegRdids, datasource.getValue());
                return Result.ERRORT(rtnmsg.getReturncode(), rtnmsg.getReturnmsg());
            }
        } catch (Exception e) {
            // TODO 加报警，需要人工处理
            log.error("{}调用税控开电子发票成功，插入数据库异常，业务编号：{}", datasource.getValue(), transactionFlowMerge.getYWBH(), e);
            return Result.ERROR();
        }
    }
    /**
     * 拼接数电票参数
     * @param transactionFlowMerge
     * @param wkpFlowList
     * @param dataSource
     * @return 返回数电票调用结果
     */
    private List<VmsFullOutInvoiceInfoDto> buildSdpParam(TransactionFlowVO transactionFlowMerge,
                                                         List<TransactionFlowVO> wkpFlowList,
                                                         VmsFullBswjManager bswj, CommonEnum dataSource) {

        VmsFullOutInvoiceInfoDto sdpDto = new VmsFullOutInvoiceInfoDto();
        // 数电发票主信息
        VmsFullOutInvoiceDetails detail = new VmsFullOutInvoiceDetails();
        // 数电发票明细信息
        List<VmsFullOutInvoiceItems> itemList = new ArrayList<>();
        sdpDto.setVmsFullOutInvoiceDetails(detail);
        sdpDto.setVmsFullOutInvoiceItemsList(itemList);

        String jyjg = transactionFlowMerge.getJYJG();
        String dataSourceValue = dataSource.getValue();

        // 个人业务标志
        List<TransactionFlowVO> notGrywList = wkpFlowList.stream()
                .filter(flow -> StringUtil.isNotBlank(flow.getISGRYW()) && !"是".equals(flow.getISGRYW()))
                .collect(Collectors.toList());
        Boolean isGryw = CollectionUtil.isEmpty(notGrywList);

        // 流水开票-非必填字段扩展信息对象
        VmsFullOutInvoiceItemsExp vmsManualExtendDto = new VmsFullOutInvoiceItemsExp();
        vmsManualExtendDto.setGmfzrrbz(isGryw ? CommonEnum.PERSON_FLAG_01.getKey() :CommonEnum.PERSON_FLAG_02.getKey());
        vmsManualExtendDto.setQydm(bswj.getQydm());
        sdpDto.setVmsFullOutInvoiceItemsExp(vmsManualExtendDto);

        VmsEnterpriseInfo enterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(jyjg);
        if(enterpriseInfo == null){
            throw new BusinessException(ResponseEnum.INTERFACE_ENT_INFO_ERROR1);
        }
        detail.setLzfpbz(LzfpbzEnum.BULE.getKey());
        detail.setFppz(CommonEnum.INVOICE_TYPE_02.getKey());
        detail.setJems(CommonEnum.AMOUNT_MODE_01.getKey());
        detail.setGmfmc(transactionFlowMerge.getKFHM());
        detail.setGmfnsrsbh(transactionFlowMerge.getNSRSBH());
        detail.setXsfmc(enterpriseInfo.getNsrmc());
        detail.setXsfnsrsbh(enterpriseInfo.getNsrsbh());
        detail.setKpr(bswj.getJkkpkpr());
        detail.setKprq(new Date());
        detail.setBz(transactionFlowMerge.getKpbz());
        detail.setSczt(CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey());
        detail.setFpzt(CommonEnum.INVOICE_STATUS_0.getKey());
        detail.setQydjid(jyjg);
        detail.setSjly(dataSource.getKey());
        detail.setPpzt(CommonEnum.MATCHING_STATUS_1.getKey());
        detail.setSfbdc(CommonEnum.SFBDC_NO.getKey());
        detail.setZsfs(CommonEnum.TAXATION_METHOD_0.getKey());
        detail.setKpzt(CommonEnum.KPZT_0.getKey());
        detail.setDelFlag(CommonEnum.DEL_STATUS_0.getKey());
        detail.setCreatTime(new Date());
        detail.setUpdateTime(new Date());
        detail.setCreatBy(dataSourceValue);
        detail.setUpdateBy(dataSourceValue);

        // 设置 合计金额 合计税额
        detail.setHjje(transactionFlowMerge.getBHSJE());
        detail.setHjse(transactionFlowMerge.getXXSE());
        detail.setJshj(transactionFlowMerge.getJYJE());

        // 发票明细：交易流水根据税率进行分组
        Map<BigDecimal, List<TransactionFlowVO>> collect = wkpFlowList.stream().collect(Collectors.groupingBy(TransactionFlowVO::getSYSL));
        Map<BigDecimal, VmsEpsInformation> espMap = this.buildEpsMap(collect, dataSourceValue);
        Map<BigDecimal, TransactionFlowVO> fpmxMap = new HashMap<>();
        // 查询产品名称、交易流水根据税率进行合并
        collect.keySet().forEach(sl -> {
            List<TransactionFlowVO> slFlowList =  collect.get(sl);
            TransactionFlowVO fpmx = new TransactionFlowVO();
            BeanUtils.copyBeanProp(fpmx, slFlowList.get(0));
//            TransactionFlowVO fpmx = slFlowList.get(0);
            fpmx.setJYRMBJE(slFlowList.stream().map(TransactionFlowVO::getJYRMBJE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setBHSJE(slFlowList.stream().map(TransactionFlowVO::getBHSJE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setXXSE(slFlowList.stream().map(TransactionFlowVO::getXXSE).reduce(BigDecimal.ZERO, BigDecimal::add));
            fpmx.setJYJE(slFlowList.stream().map(TransactionFlowVO::getJYJE).reduce(BigDecimal.ZERO, BigDecimal::add));
            VmsEpsInformation eps = espMap.get(sl);
            fpmx.setCpmc("*" + eps.getSphfwfljc() + "*" + eps.getEpsName());
            fpmx.setRdidsStr(slFlowList.stream().map(vo -> vo.getRDID().toString()).collect(Collectors.joining("、")));

            if (fpmx.getJYRMBJE().compareTo(new BigDecimal("0")) <= 0) {
                throw new BusinessException(ResponseEnum.OFFICIAL_JYJE_ERROR);
            }
            fpmxMap.put(sl, fpmx);
        });

        List<BigDecimal> fpmxKeys = new ArrayList<>(fpmxMap.keySet());
        for (int i = 0; i < fpmxKeys.size(); i++) {
            TransactionFlowVO fpmx = fpmxMap.get(fpmxKeys.get(i));
            VmsFullOutInvoiceItems item = new VmsFullOutInvoiceItems();
            itemList.add(item);

            item.setXmmc(fpmx.getCpmc());
            item.setMxxh((long) i + 1);
            item.setGgxh(fpmx.getYWBH());
            item.setDw(fpmx.getJLDW());
            item.setSl(CommonConstant.STR_1);
            item.setHsdj(fpmx.getJYJE().toPlainString());
            item.setDj(fpmx.getBHSJE().toPlainString());
            item.setJe(fpmx.getBHSJE());
            item.setSlv(fpmx.getSYSL());
            item.setSe(fpmx.getXXSE());
            item.setFphxz(CommonEnum.FPHXZ_00.getKey());
            item.setCreatTime(new Date());
            item.setCreatBy(dataSourceValue);
            VmsEpsInformation eps = espMap.get(fpmxKeys.get(i));
            if (ObjectUtil.isNotEmpty(eps)) {
                item.setCpbm(eps.getEpsCode());
                if (StringUtil.isNotEmpty(eps.getGstcmCode())) {
                    item.setSphfwssflhbbm(eps.getGstcmCode());
                }
                if (StringUtil.isNotEmpty(eps.getJsff())) {
                    item.setJsff(eps.getJsff());
                }
                if (StringUtil.isNotEmpty(eps.getZsxm())) {
                    item.setZsxm(eps.getZsxm());
                }
                if (StringUtil.isNotEmpty(eps.getYhzcbs())) {
                    item.setYhzcbs(eps.getYhzcbs());
                }
            }

            item.setRdid(fpmx.getRdidsStr());
        }
        List<VmsFullOutInvoiceInfoDto> vmsFullOutInvoiceInfoDtos = new ArrayList<>();
        vmsFullOutInvoiceInfoDtos.add(sdpDto);

        return vmsFullOutInvoiceInfoDtos;

    }

    private Map<BigDecimal, VmsEpsInformation> buildEpsMap(Map<BigDecimal, List<TransactionFlowVO>> collect, String dataSourceValue) {
        // TODO 后续优化方案：CommonEnum独立一个枚举，然后使用 CommonEnum。getValue(sl)
        Map<BigDecimal, VmsEpsInformation> espMap = new HashMap<>();
        collect.keySet().forEach(sl -> {
            BigDecimal sl4 = sl.setScale(4);
            VmsEpsInformation epsInformation6 = epsInformationService.getInfoBySlvJyjg(sl4.toString(), collect.get(sl).get(0).getJYJG());
            if (epsInformation6 == null) {
                log.error("{}出现业务异常，获取企业商品信息为空，sl={}", dataSourceValue, sl4);
                throw new BusinessException(ResponseEnum.OFFICIAL_CONFIG_ERROR);
            }
            espMap.put(sl, epsInformation6);
        });
        return espMap;
    }

    private Map<BigDecimal, NvatSxcpbXinhua> buildOldEpsMap(Map<BigDecimal, List<TransactionFlowVO>> collect, String dataSourceValue) {
        Map<BigDecimal, NvatSxcpbXinhua> epsXinhuaMap = new HashMap<>();
        collect.keySet().forEach(sl -> {
            BigDecimal sl4 = sl.setScale(4);
            NvatSxcpbXinhua byCpbm = nvatSxcpbXinhuaService.getByCpbm(sl4.toString());
            if (byCpbm == null) {
                log.error("{}出现业务异常，获取企业商品信息为空，sl={}", dataSourceValue, sl4);
                throw new BusinessException(ResponseEnum.OFFICIAL_CONFIG_ERROR);
            }
            epsXinhuaMap.put(sl, byCpbm);
        });
        return epsXinhuaMap;
    }

    /**
     * 开具电子发票
     * @param transactionFlowMerge
     * @return
     */
    private BussinessBO buildBussinessBO(TransactionFlowVO transactionFlowMerge, List<Long> wkpRdids,
                                         Map<BigDecimal, TransactionFlowVO> fpmxMap, Map<BigDecimal, NvatSxcpbXinhua> epsXinhuaMap) {
        String jyjg = transactionFlowMerge.getJYJG();
        BussinessBO bussinessBO = new BussinessBO();
        BussinessBO.CUSTOMDATA.DDXX ddxx = new BussinessBO.CUSTOMDATA.DDXX();
        ddxx.setGMF_SJH(transactionFlowMerge.getSJH());
        ddxx.setGMF_DZYX(transactionFlowMerge.getDZYX());
        String ZJLX = transactionFlowMerge.getZJLX();
        if ("0".equals(ZJLX)) {
            ZJLX = "01";
        } else if ("1".equals(ZJLX)) {
            ZJLX = "02";
        } else if ("2".equals(ZJLX)) {
            ZJLX = "03";
        } else {
            ZJLX = "07";
        }
        ddxx.setGMF_SFZJLX(ZJLX);
        ddxx.setGMF_SFZJHM(transactionFlowMerge.getZJHM());
        ddxx.setGMF_XM(transactionFlowMerge.getKFHM());
        ddxx.setGMF_DZYX("");
        String fpqqlsh = this.buildFpqqlsh(wkpRdids, transactionFlowMerge.getRDID());
        ddxx.setDDBH(fpqqlsh);
        ddxx.setHTBH(fpqqlsh);
        List<BussinessBO.CUSTOMDATA.DDXX> ddxxes = new ArrayList<>();
        ddxxes.add(ddxx);
        BussinessBO.CUSTOMDATA.DDXXS ddxxs = new BussinessBO.CUSTOMDATA.DDXXS();
        ddxxs.setDDXX(ddxxes);
        BussinessBO.CUSTOMDATA customdata = new BussinessBO.CUSTOMDATA();
        customdata.setDDXXS(ddxxs);
        bussinessBO.setCUSTOMDATA(customdata);

        BussinessBO.REQUEST_COMMON_FPKJ REQUEST_COMMON_FPKJ = new BussinessBO.REQUEST_COMMON_FPKJ();
        bussinessBO.setREQUEST_COMMON_FPKJ(REQUEST_COMMON_FPKJ);
        // 发票信息
        BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_FPT COMMON_FPK_JFPT = new BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_FPT();
        REQUEST_COMMON_FPKJ.setCOMMON_FPKJ_FPT(COMMON_FPK_JFPT);
        // 发票明细
        BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXXS COMMON_FPKJ_XMXXS = new BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXXS();
        REQUEST_COMMON_FPKJ.setCOMMON_FPKJ_XMXXS(COMMON_FPKJ_XMXXS);

        List<BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXX> COMMON_FPKJ_XMXXList = new ArrayList<>();
        COMMON_FPKJ_XMXXS.setCOMMON_FPKJ_XMXX(COMMON_FPKJ_XMXXList);


        KpjgInfoVO kpjgInfoVO = nvatTrandtadvaltaxsepService.queryKpjgInfoByJyjg(jyjg);
        COMMON_FPK_JFPT.setBZ(transactionFlowMerge.getKpbz());
        COMMON_FPK_JFPT.setBMB_BBH("");
        COMMON_FPK_JFPT.setFHR(kpjgInfoVO.getFHRY());

        COMMON_FPK_JFPT.setGMF_DZDH("");
        COMMON_FPK_JFPT.setGMF_NSRSBH("");
        COMMON_FPK_JFPT.setGMF_MC(transactionFlowMerge.getKFHM());
        COMMON_FPK_JFPT.setGMF_YHZH("");

        COMMON_FPK_JFPT.setHJJE(transactionFlowMerge.getBHSJE().toString());
//        COMMON_FPK_JFPT.setHJSE("0");
        COMMON_FPK_JFPT.setHJSE(transactionFlowMerge.getXXSE().toString());
        COMMON_FPK_JFPT.setJSHJ(transactionFlowMerge.getJYJE().toString());
        COMMON_FPK_JFPT.setKCE("");
        COMMON_FPK_JFPT.setKPLX(transactionFlowMerge.getLSXZ().equals(2) ? "1" : "0");
        COMMON_FPK_JFPT.setKPR(kpjgInfoVO.getKPRY());
        COMMON_FPK_JFPT.setSKR(kpjgInfoVO.getSKRY());

        COMMON_FPK_JFPT.setXSF_DZDH(kpjgInfoVO.getLXDZ() + kpjgInfoVO.getLXDH());
        COMMON_FPK_JFPT.setXSF_NSRSBH(kpjgInfoVO.getNSSBH());
        COMMON_FPK_JFPT.setXSF_MC(kpjgInfoVO.getSBDWMC());
        COMMON_FPK_JFPT.setXSF_YHZH(kpjgInfoVO.getKHYH() + kpjgInfoVO.getYHZH());
        COMMON_FPK_JFPT.setYFP_DM("");
        COMMON_FPK_JFPT.setYFP_HM("");
        COMMON_FPK_JFPT.setZSFS(transactionFlowMerge.getZSFS().toString());


        // * ③查询交易流水+寿险产品表，得到发票明细数据，并根据sl进行合并

        // 交易明细数据
        fpmxMap.forEach((key, value) -> {
            NvatSxcpbXinhua nvatSxcpbXinhua = epsXinhuaMap.get(key);
            BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXX COMMON_FPKJ_XMXX = new BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXX();
            COMMON_FPKJ_XMXX.setFPHXZ("0");
            COMMON_FPKJ_XMXX.setSL(StringUtil.toString(key));
            COMMON_FPKJ_XMXX.setSE(new BigDecimal(0).compareTo(key) == 0 ? "0" : StringUtil.toString(value.getXXSE()));
            COMMON_FPKJ_XMXX.setDW(value.getJLDW());
            COMMON_FPKJ_XMXX.setGGXH(value.getGGXH());
            COMMON_FPKJ_XMXX.setLSLBS(nvatSxcpbXinhua.getLslbs() == null ? "" : nvatSxcpbXinhua.getLslbs().toString());
            COMMON_FPKJ_XMXX.setSPBM(nvatSxcpbXinhua.getSpbm());
            COMMON_FPKJ_XMXX.setXMDJ(StringUtil.toString(value.getBHSJE()));
            COMMON_FPKJ_XMXX.setXMJE(StringUtil.toString(value.getBHSJE()));
            COMMON_FPKJ_XMXX.setXMMC(value.getCpmc());
            COMMON_FPKJ_XMXX.setXMSL("1");
            COMMON_FPKJ_XMXX.setZXBM("");
            boolean yhzc = nvatSxcpbXinhua.getYhzcbs() != null && !"0".equals(nvatSxcpbXinhua.getYhzcbs().toString());
            COMMON_FPKJ_XMXX.setZZSTSGL(yhzc ? "免税" : "");
            COMMON_FPKJ_XMXX.setYHZCBS(yhzc ? "1" : "0");
            COMMON_FPKJ_XMXXList.add(COMMON_FPKJ_XMXX);
        });
        return bussinessBO;
    }

    private String buildFpqqlsh(List<Long> wkpRdids, Long mergeId) {
        List<InvoiceInfoVO> invoiceInfoList = nvatOutinvoicedetailsService.queryInvoiceBYRdids(wkpRdids);
        Map<Long, List<InvoiceInfoVO>> rdidInvoiceMap = invoiceInfoList.stream().collect(Collectors.groupingBy(InvoiceInfoVO::getRDID));
        String makeupZero = "";
        int lenOid = 20;
        List<InvoiceInfoVO> mergeRdidInvoiceList = rdidInvoiceMap.get(mergeId);
        if (CollectionUtil.isNotEmpty(mergeRdidInvoiceList)) {
            boolean temp = true;
            for(InvoiceInfoVO m : mergeRdidInvoiceList){
                String fpzt = StringUtil.toString(m.getFPZT());
                if("1".equals(fpzt)){
                    temp = false;
                    break;
                }
            }
            if(temp){
                makeupZero = "CX" + mergeRdidInvoiceList.size();
                lenOid -= 3;
            }
        }
        if (mergeId.toString().length() < lenOid) {
            int len = lenOid - mergeId.toString().length();
            for (int i = 0; i < len; i++) {
                makeupZero += "0";
            }
        }
        return makeupZero + mergeId;
    }
    private Rtnmsg dzfpPostXml(BussinessBO bussinessBO) {
        String fpqqlsh = bussinessBO.getCUSTOMDATA().getDDXXS().getDDXX().get(0).getHTBH();
        StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"gbk\"?><business id=\"FPKJ\">");
        String xml = XML.toXml(JSONUtil.parseObj(bussinessBO));
        sb.append(xml);
        sb.append("</business>");
        String sendXml = sb.toString().replace("<DDXXS>", "<DDXXS LSH=\"" + fpqqlsh + "\">");

        String sendUrl = biDataConfigInfoService.getESendUrlPrefix();
        String sendResult = this.postSendXML(sendXml, sendUrl);

        JSONObject entries = XML.toJSONObject(sendResult);
        Object rtnmsg1 = entries.get("rtnmsg");

        Rtnmsg rtnmsg = ((JSONObject) rtnmsg1).toBean(Rtnmsg.class);

        return rtnmsg;
    }
    /**
     * 调用电子发票平台接口，开电子发票
     * @param issueXml
     * @param postAddress
     * @return
     */
    private String postSendXML(String issueXml, String postAddress) {
        log.info("电子发票接口请求，请求地址：{}，请求入参：{}", postAddress, issueXml);
        HttpURLConnection httpUrlConnection = null;
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(postAddress);
            httpUrlConnection = (HttpURLConnection) url.openConnection();
            httpUrlConnection.setRequestProperty("BWTS", "");
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setDoInput(true);// 设置是否从httpUrlConnection读入，默认情况下是true;
            httpUrlConnection.setUseCaches(false);// Post 请求不能使用缓存
            httpUrlConnection.setConnectTimeout(60 * 1000); // 连接时间
            httpUrlConnection.setReadTimeout(60 * 1000); // 响应接受时间
            httpUrlConnection.setRequestProperty("Content-type","application/xml;charset=gbk");
            httpUrlConnection.setRequestMethod("POST");
            httpUrlConnection.connect();
            byte[] data = issueXml.getBytes("gbk");
            DataOutputStream out = new DataOutputStream(httpUrlConnection.getOutputStream());
            out.write(data); // 写入请求的字符串
            out.flush();
            out.close();

            if (httpUrlConnection.getResponseCode() == 200) {
                log.info("电子发票接口请求成功，请求地址：{}，请求入参：{}", postAddress, issueXml);
                // 请求返回的数据
                InputStream in = httpUrlConnection.getInputStream();
                System.out.println(in.toString());
                BufferedReader reader = new BufferedReader(new InputStreamReader(in, "gbk"));
                String s = "";
                while ((s = reader.readLine()) != null) {
                    result.append(s);
                }
                reader.close();
            } else {
                log.info("电子发票接口请求失败，请求地址：{}，请求入参：{}", postAddress, issueXml);
            }
        } catch (Exception e) {
            log.error("电子发票接口请求失败，请求地址：{}，请求入参：{}", postAddress, issueXml,e);
            throw new BusinessException(ResponseEnum.OFFICIAL_DZFPPT_ERROR);
        } finally {
            if (httpUrlConnection != null) {
                httpUrlConnection.disconnect();
            }
        }
        log.info("电子发票接口请求，请求地址：{}，返回结果：{}", postAddress, result);
//        String sendResult = "<?xml version=\"1.0\" encoding=\"gbk\"?><rtnmsg><returncode>4000</returncode><returnmsg>成功</returnmsg><returndata><fpdm>dcy022001600111</fpdm><fphm>dcy03060308</fphm><kprq>20240424202132</kprq></returndata></rtnmsg>";
//        return sendResult;
        return result.toString();
    }


    private boolean updateDatabase(List<Long> wkpRdids, List<Long> wkpNegRdids, String dataSource) {
        int result = nvatTrandtadvaltaxsepService.updateLsztByRdids(3, wkpRdids, 1, true);
        boolean updateLszt = result == wkpRdids.size();
        if (updateLszt && CollectionUtil.isNotEmpty(wkpNegRdids)) {
            negativestreamService.updateByRdids(wkpNegRdids, dataSource);
            return updateLszt;
        }
        return updateLszt;
    }
    private boolean rollbackDatabase(List<TransactionFlowVO> wkpVos, List<Long> wkpNegRdids, String dataSource) {
        log.info("{}开票返回失败，回滚交易流水和负数流水处理状态。业务流水号：{}, 负数处理rdids：{}", dataSource, wkpVos.get(0).getYWBH(), wkpNegRdids);
        List<NvatTrandtadvaltaxsep>  jylsList = new ArrayList<>();
        wkpVos.forEach(flow -> {
            NvatTrandtadvaltaxsep ls = new NvatTrandtadvaltaxsep();
            ls.setRdid(flow.getRDID());
            ls.setWkpje(flow.getWKPJE());
            ls.setLszt(1L);
            jylsList.add(ls);
        });
        boolean updateLszt = nvatTrandtadvaltaxsepService.rollbackLszt(jylsList);
        if (updateLszt && CollectionUtil.isNotEmpty(wkpNegRdids)) {
            return negativestreamService.rollbackByRdids(wkpNegRdids);
        }
        return updateLszt;
    }
    /** 7.更新数据库
     *    保存发票主表、
     *    保存发票明细表、
     *    保存流水关联表
     */
    private boolean insertDatabase(BussinessBO bussinessBO,
                                   Map<BigDecimal, List<TransactionFlowVO>> wkpFlowList,
                                   TransactionFlowVO transactionFlowMerge, Rtnmsg rtnmsg, Map<BigDecimal, NvatSxcpbXinhua> epsXinhuaMap,
                                   CommonEnum datasource) {
        // 保存老VMS发票主表信息
        String jyjg = transactionFlowMerge.getJYJG();
        KpjgInfoVO kpjgInfoVO = nvatTrandtadvaltaxsepService.queryKpjgInfoByJyjg(jyjg);

        NvatOutInvoiceDetails detail = new NvatOutInvoiceDetails();
        BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_FPT fp = bussinessBO.getREQUEST_COMMON_FPKJ().getCOMMON_FPKJ_FPT();
        BussinessBO.CUSTOMDATA.DDXXS ddxx = bussinessBO.getCUSTOMDATA().getDDXXS();
        //        INSERT INTO NVAT_OUTINVOICEDETAILS (OIDID, FPQQLSH, KPWDBM, SBDWID, KPDW, FPZL, KPRY, KPRQ, KPSQ, SPFMC, SPFSBH,
//        SPFYHZH, SPFDZDH, KPBZ, SKRY, FHRY, FPZT, SFQDKP, KPZT, SJLY, SFYHZ, QYDJID, FPLXDM, TSPZ, HJJE, HJSE, JSHJ, FPMJ,
//        YWLXBM, ZSFS,KCE,KPNSRSBH,KPDDZDH,KPKHHZH,KHSJH,KHEMAIL,FPDM,FPHM,ZJLX,ZJHM,EXPCOL2)
//        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, TO_CHAR(SYSDATE,'YYYYMMDD'))";
        Long oidId = sequenceService.getSequence(CommonConstant.TABLE_NVAT_OUTINVOICEDETAILS);
        detail.setOidid(oidId);
        detail.setFpqqlsh(ddxx.getDDXX().get(0).getHTBH());
        detail.setKpwdbm(kpjgInfoVO.getKPWDBM()); //
        detail.setSbdwid(kpjgInfoVO.getSBDWID());
        detail.setKpdw(kpjgInfoVO.getSBDWMC());
        detail.setFpzl("11");
        detail.setKpry(fp.getKPR());
        Date now = new Date();
        detail.setKprq(now);
        detail.setKpsq(DateUtil.format(now, "yyyyMM"));
        detail.setSpfmc(fp.getGMF_MC());
        detail.setSpfsbh(fp.getGMF_NSRSBH());
        detail.setSpfyhzh(fp.getGMF_YHZH()); //
        detail.setSpfdzdh(fp.getGMF_DZDH()); //
        detail.setKpbz(fp.getBZ());
        detail.setSkry(fp.getSKR()); //
        detail.setFhry(fp.getFHR());
        detail.setFpzt(Integer.parseInt(CommonEnum.SK_INVOICE_STATUS_1.getKey()));
        detail.setSfqdkp(0);
        detail.setKpzt(Integer.parseInt(CommonEnum.KPZT_2.getKey()));
        detail.setSjly(Integer.parseInt(datasource.getKey()));
        detail.setSfyhz(1); //
        detail.setQydjid(jyjg);
        detail.setFplxdm(CommonEnum.INVOICE_TYPE_026.getKey());
        detail.setTspz("00");
        detail.setHjje(new BigDecimal(fp.getHJJE()));
        detail.setHjse(new BigDecimal(fp.getHJSE()));
        detail.setJshj(new BigDecimal(fp.getJSHJ()));
        detail.setFpmj("2");
        detail.setYwlxbm(transactionFlowMerge.getYWLXBM()); //
        detail.setZsfs(0);
        detail.setKce(new BigDecimal(0)); //
        detail.setFphm(rtnmsg.getReturndata().getFphm());
        detail.setKpnsrsbh(fp.getXSF_NSRSBH());
        detail.setKpddzdh(fp.getXSF_DZDH()); //
        detail.setKpkhhzh(fp.getXSF_YHZH()); //
        detail.setKhsjh(transactionFlowMerge.getSJH()); //
        detail.setKhemail(transactionFlowMerge.getDZYX()); //
        detail.setFpdm(rtnmsg.getReturndata().getFpdm());
        detail.setFphm(rtnmsg.getReturndata().getFphm());
        detail.setZjlx(transactionFlowMerge.getZJLX()); //
        detail.setZjhm(transactionFlowMerge.getZJHM()); //
        detail.setExpcol2(DateUtils.formatDate(now, "yyyyMMdd")); //

//        Long oidId = nvatOutInvoiceService.insertNvatOutInvoiceDetails(detail, jyjg, rtnmsg.getReturndata().getFpdm());
        nvatOutinvoicedetailsService.insertDetail(detail);

        // 交易明细数据
//        String outInvoiceItemsSql = "INSERT INTO NVAT_OUTINVOICEITEMS "
//                + "(IVIID,CPBM,SPMC,GGXH,JLDW,DJ,GMSL,JE,SL,SE,HSDJ,HSJE,OIDID,FPHXZ,LSLBS,YHZCBS,ZZSTSGL,SPBM,ZXBM) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

        Map<BigDecimal, Long> slIvvidMap = new HashMap<>();
        List<BussinessBO.REQUEST_COMMON_FPKJ.COMMON_FPKJ_XMXX> fpmxList = bussinessBO.getREQUEST_COMMON_FPKJ().getCOMMON_FPKJ_XMXXS().getCOMMON_FPKJ_XMXX();
        fpmxList.forEach(fpmx -> {
            NvatOutInvoiceItems item =  new NvatOutInvoiceItems();
            Long iviid = sequenceService.getSequence(CommonConstant.TABLE_NVAT_OUTINVOICEITEMS);
            item.setIviid(iviid);
            item.setSpmc(fpmx.getXMMC());
            item.setGgxh(fpmx.getGGXH());
            item.setJldw(fpmx.getDW());
            item.setDj(new BigDecimal(fpmx.getXMDJ()));
            item.setGmsl(new BigDecimal(1));
            item.setSl(new BigDecimal(fpmx.getSL()));
            item.setJe(new BigDecimal(fpmx.getXMJE()));
            item.setSe(new BigDecimal(fpmx.getSE()));
            BigDecimal dj = new BigDecimal(fpmx.getXMJE()).add(new BigDecimal(fpmx.getSE()));
            item.setHsdj(dj);
            item.setHsje(dj);
            item.setOidid(oidId);
            item.setFphxz("0");
            item.setYhzcbs(!"0".equals(fpmx.getYHZCBS()) ? 1 : Integer.parseInt(fpmx.getYHZCBS()));
            item.setZzstsgl(fpmx.getZZSTSGL());
            item.setSpbm(fpmx.getSPBM());

            NvatSxcpbXinhua epsXinhua = epsXinhuaMap.get(item.getSl());
            item.setZsxm(epsXinhua.getZsxm());
            item.setJsff(epsXinhua.getJsff());
            item.setCpbm(epsXinhua.getCpbm());
            item.setLslbs(StringUtil.isEmpty(epsXinhua.getLslbs()) ? null : epsXinhua.getLslbs().intValue());

            // 保存发票明细信息
            nvatOutInvoiceItemsMapper.insert(item);
            slIvvidMap.put(item.getSl(), iviid);
        });

        List<NvatRevmapinvoitems> revIterms = new ArrayList<>();
        // 批量保存流水发票关联关系表
        wkpFlowList.forEach((key, flowList) -> {
            flowList.forEach(flow -> {
                NvatRevmapinvoitems nvatRevmapinvoitems = new NvatRevmapinvoitems();
                nvatRevmapinvoitems.setNrmivid(sequenceService.getSequence(CommonConstant.NVAT_REVMAPINVOITEMS));
                nvatRevmapinvoitems.setOidid(oidId);
                nvatRevmapinvoitems.setIviid(slIvvidMap.get(key));
                nvatRevmapinvoitems.setRdid(flow.getRDID());
                revIterms.add(nvatRevmapinvoitems);
            });
        });

        return nvatRevmapinvoitemsService.saveBatch(revIterms);
    }

}
